﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Dynamic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace DotNetCommon.Extensions;

/// <summary>
/// 通用扩展方法
/// </summary>
public static class GenericExtensions
{
    /// <summary>
    /// 判断当前对象是否所属 <seealso cref="Type"/> 的默认值
    /// </summary>
    public static bool IsDefault<T>(this T @object) => EqualityComparer<T>.Default.Equals(@object, default);

    /// <summary>
    /// 获取符合条件的属性名集合
    /// </summary>
    /// <param name="object"></param>
    /// <param name="includePrivate">是否包含私有属性</param>
    /// <param name="inherit">是否包含继承属性</param>
    public static string[] GetPropertyNames<T>(this T @object, bool inherit = true, bool includePrivate = true)
    {
        if (@object is IDynamicMetaObjectProvider expando)
        {
            var dic = (IDictionary<string, object>)expando;
            return [.. dic.Keys];
        }

        return @object.GetType()
            .GetInstanceProperties(inherit, includePrivate)
            .Select(p => p.Name).ToArray();
    }

    /// <summary>
    /// 提供一个具有超时功能的锁
    /// </summary>
    public static Locker Lock<T>(this T obj, TimeSpan timeout) where T : class
    {
        var lockTaken = false;

        try
        {
            Monitor.TryEnter(obj, timeout, ref lockTaken);
            if (lockTaken) { return new Locker(obj); }
            throw new TimeoutException("Failed to acquire a lock within the timeout period of: " + timeout.ToString());
        }
        catch
        {
            if (lockTaken) { Monitor.Exit(obj); }
            throw;
        }
    }

    /// <summary>
    /// 具有超时功能的锁
    /// </summary>
    public struct Locker : IDisposable
    {
        private readonly object _obj;

        /// <summary>
        /// Returns an instance of <see cref="Locker"/>.
        /// </summary>
        /// <param name="obj">The <c>object</c> on which lock is taken.</param>
        internal Locker(object obj) => _obj = obj;

        /// <summary>
        /// Releases any locks taken by this instance.
        /// </summary>
        public void Dispose() => Monitor.Exit(_obj);
    }

    /// <summary>
    /// 将当前对象封住为一个完成态的Task <c>Task.FromResult(this)</c>
    /// </summary>
    [DebuggerStepThrough]
    public static Task<T> ToCompletedTask<T>(this T result) => Task.FromResult(result);

    /// <summary>
    /// Creates a ValueTask that's completed successfully with the specified <paramref name="result"/>.
    /// </summary>
    [DebuggerStepThrough]
    public static ValueTask<T> ToCompletedValueTask<T>(this T result) => new(result);

    /// <summary>
    /// 返回自身, obj=>obj, 可作为表达式解析的标记, 如:
    /// <code>
    /// i=>i.Children.Add(new Node{Id=2,Name="test"}.Eval())
    /// </code>
    /// </summary>
    /// <remarks>
    /// 应用实例: 在 ExpressionHelper.ReduceLambda() 中, 将默认对 Eval 前的部分进行求值简化
    /// </remarks>
    [DebuggerStepThrough]
    public static T Eval<T>(this T obj) => obj;
}